#!/usr/bin/env bash

set -e

#节点环境
ENV="test"
#程序目录
INSTALL_DIR=/opt/enode
#数据存放目录
DATA_DIR=/data_dir/enode_store

#卫星服务
#CENTER_SERVER="101.37.33.124"
#包管理服务地址
NODE_SERVER="http://upgrade.guanjieai.com"
CONTACT_ADDR="wss://estore.guanjieai.com:10002/heartbeat"

UpgradeCheckTime="1h"

#停止旧的服务
stopService() {
  systemctl stop enode
  systemctl stop enode_upgrade_timer.timer
}

startService() {
  systemctl start enode
  systemctl start enode_upgrade_timer.timer
}

#获取最新版本
getLatest() {
  set +e
  res=`curl  -s -X POST -F "env=${ENV}" -F "os=${1}"  -F "arch=${2}"  ${NODE_SERVER}/node/latest`
  if [ $? != 0 ]; then
    echo "获取最新enode失败(curl  -s -X POST -F \"env=${ENV}\" -F \"os=${1}\"  -F \"arch=${2}\"  ${NODE_SERVER}/node/latest)"
  fi
  set -e
  echo $res
}

#获取架构
getArch() {
   arch=""
   case $(uname -m) in
       aarch64)   arch="arm64" ;;
       x86_64) arch="amd64" ;;
       arm)    dpkg --print-architecture | grep -q "arm64" && arch="arm64" || arch="arm" ;;
   esac
   echo $arch
}
#获取OS
getOs() {
  echo `echo $(uname) | awk '{print tolower($0)}'`
}

#下载
download() {
  zipUrl=$1
  zipPath=$2
  rm -f $zipPath
  wget ${zipUrl} -O ${zipPath}
  if [ ! -f "${zipPath}" ]; then
    echo "安装包下载失败:${zipUrl}"
    exit 1
  fi
}

#节点配置setup
nodeSetup() {
  nodeBin="${INSTALL_DIR}/enode"
  if [ ! -f "${nodeBin}" ]; then
    echo "enode 程序不存在"
    exit 1
  fi
  cmd="${nodeBin} setup --defaults=${ENV} --config=${INSTALL_DIR}/config.yaml --contact.heartbeat-addr=${CONTACT_ADDR}"
  echo -e "\n${cmd} => $?\n"
  $cmd
  #echo "配置文件 " ${DATA_DIR}/config.yaml
}

initNode() {
  #下载的包解压到程序目录
  zipFilePath=${1}
  rm -rf ${INSTALL_DIR}
  unzip -o ${zipFilePath} -d ${INSTALL_DIR}
  cd $INSTALL_DIR
  chmod +x enode
  #旧的安装目录清理
  rm -rf $DATA_DIR
  mkdir -p $DATA_DIR
  #node setup
  nodeSetup
}

updateServiceFile() {
  cd $INSTALL_DIR
  ServerName="${1}.service"
  sed -i "s#HOME#${INSTALL_DIR}#g;s#LOG_FILE#${INSTALL_DIR}/enode.log#g;s#ENV#${ENV}#g" ${ServerName}
  cd -
}

installService() {
  # 安装服务
  cd $INSTALL_DIR
  echo "install " ${1}
  ServerName=${1}.service
  updateServiceFile "${1}"
  rm -f /etc/systemd/system/${ServerName}
  ln -s ${INSTALL_DIR}/${ServerName} /etc/systemd/system/${ServerName}
  systemctl daemon-reload
  systemctl enable $1
}

updateNodeUpgradeServiceFile() {
  cd $INSTALL_DIR
  pyt=`which python3`
  [ "${pyt}" == "" ] && pyt=`which python`
  ServerName="${1}.service"
  sed -i "s#HOME#${INSTALL_DIR}#g;s#PYTHON#${pyt}#g;s#ENV#${ENV}#g" ${ServerName}
  ServerName="${1}.timer"
  sed -i "s#TIME#${UpgradeCheckTime}#g" ${ServerName}
  cd -
}


installNodeUpgradeService() {
  # 安装服务
  cd $INSTALL_DIR
  echo "install " ${1}
  updateNodeUpgradeServiceFile "${1}"
  ServerName=${1}.service
  ServerTimerName=${1}.timer
  rm -f /etc/systemd/system/${ServerName}
  ln -s ${INSTALL_DIR}/${ServerName} /etc/systemd/system/${ServerName}
  rm -f /etc/systemd/system/${ServerTimerName}
  ln -s ${INSTALL_DIR}/${ServerTimerName} /etc/systemd/system/${ServerTimerName}
  systemctl daemon-reload
  systemctl enable $ServerTimerName
}


createUpdateCrontab() {
  script=${INSTALL_DIR}/enode_update.py
  pyt=`which python3`
  [ "${pyt}" == "" ] && pyt=`which python`
  crontab -l > /tmp/crontmp
  cmd="${pyt} ${script} ${ENV} >${INSTALL_DIR}/enode_update.log 2>&1"
  cmd="flock -xn ${INSTALL_DIR}/enode_update.lock -c \"${cmd}\""
  #删除之前的
  sed -i "/enode_update\.py/d" /tmp/crontmp
  found=`grep -c "${cmd}" /tmp/crontmp`
  if [ $found -eq 0 ];then
      echo "*/60 * * * * ${cmd}" >> /tmp/crontmp
      crontab /tmp/crontmp
      echo "已创建定时任务"
  fi
}

removeUpdateCrontab() {
  crontab -l > /tmp/crontmp
  #删除之前的
  sed -i "/enode_update\.py/d" /tmp/crontmp
  crontab /tmp/crontmp
}


#安装
install() {
  # 获取安装版本号
  if [ $# -lt 1 ]; then
    echo "ERROR :  请选择安装包 "
    exit 1
  fi
  echo "开始安装[${1}]"
  zipFilePath="/tmp/enode.zip"
  #下载安装包
  download ${1} ${zipFilePath}
  #停止旧服务
  set +e
  stopService
  set -e
  #初始化node
  initNode ${zipFilePath}
  #安装服务
  installNodeUpgradeService "enode_upgrade_timer"
  installService "enode"
  echo "install ok"
  #启动服务
  startService
  #创建crond
  set +e
  removeUpdateCrontab
  set -e
  echo "start node ok"
}

#更新
update() {
  # 获取更新版本号
  if [ $# -lt 1 ]; then
    echo "ERROR :  请选择安装包更新 "
    exit 1
  fi
  echo "开始更新[${1}]"
  zipFilePath="/tmp/enode.zip"
  #下载安装包
  download ${1} ${zipFilePath}
  #停止旧服务
  set +e
  stopService
  set -e
  #覆盖程序
  echo "unzip -o ${zipFilePath} -d ${INSTALL_DIR}"
  unzip -o ${zipFilePath} -d ${INSTALL_DIR}
  chmod +x ${INSTALL_DIR}/enode
  installNodeUpgradeService "enode_upgrade_timer"
  installService "enode"
  #移除check service
  set +e
  removeUpdateCrontab
  systemctl daemon-reload
  if [ $? != 0 ]; then
    echo "更新失败"
  fi
  set -e
  #启动服务
  startService
  echo "update node ok"
}

function getPkgDownloadUrl() {
  pkgUrl=""
  set +e
  if [[ $# == 0 || "${1}" == "" ]]; then
    res=`getLatest $(getOs) $(getArch)`
    code=`getJsonValuesByAwk ${res} code 0`
    msg=`getJsonValuesByAwk ${res} message ""`
    data=`getJsonValuesByAwk ${res} data ""`
    if [ $code != 0 ];then
      echo $res
      exit 1
    fi

    pkgUrl=`getJsonValuesByAwk ${data} download_url ""`
    pkgUrl=`echo ${pkgUrl} | awk '{gsub(/^"+|"+$/, "");print}'`
    if [ "${pkgUrl}" == "" ]; then
      echo "获取enode包下载地址失败"
      exit 1
    fi
  else
    pkgUrl=${1}
  fi
  set -e
  echo $pkgUrl
}

### 方法简要说明：
### 1. 是先查找一个字符串：带双引号的key。如果没找到，则直接返回defaultValue。
### 2. 查找最近的冒号，找到后认为值的部分开始了，直到在层数上等于0时找到这3个字符：,}]。
### 3. 如果有多个同名key，则依次全部打印（不论层级，只按出现顺序）
### @author lux feary
###
### 3 params: json, key, defaultValue
getJsonValuesByAwk() {
    awk -v json="$1" -v key="$2" -v defaultValue="$3" 'BEGIN{
        foundKeyCount = 0
        while (length(json) > 0) {
            # pos = index(json, "\""key"\""); ## 这行更快一些，但是如果有value是字符串，且刚好与要查找的key相同，会被误认为是key而导致值获取错误
            pos = match(json, "\""key"\"[ \\t]*?:[ \\t]*");
            if (pos == 0) {if (foundKeyCount == 0) {print defaultValue;} exit 0;}

            ++foundKeyCount;
            start = 0; stop = 0; layer = 0;
            for (i = pos + length(key) + 1; i <= length(json); ++i) {
                lastChar = substr(json, i - 1, 1)
                currChar = substr(json, i, 1)

                if (start <= 0) {
                    if (lastChar == ":") {
                        start = currChar == " " ? i + 1: i;
                        if (currChar == "{" || currChar == "[") {
                            layer = 1;
                        }
                    }
                } else {
                    if (currChar == "{" || currChar == "[") {
                        ++layer;
                    }
                    if (currChar == "}" || currChar == "]") {
                        --layer;
                    }
                    if ((currChar == "," || currChar == "}" || currChar == "]") && layer <= 0) {
                        stop = currChar == "," ? i : i + 1 + layer;
                        break;
                    }
                }
            }

            if (start <= 0 || stop <= 0 || start > length(json) || stop > length(json) || start >= stop) {
                if (foundKeyCount == 0) {print defaultValue;} exit 0;
            } else {
                print substr(json, start, stop - start);
            }

            json = substr(json, stop + 1, length(json) - stop)
        }
    }'
}

main() {
  #解析参数
  set -- $(getopt -o e: -l env: -n ${0} -u -- "$@")
  while true; do
    case "${1}" in
    -e | --env)
      ENV="${2}"
      shift
      ;;
    --)
      shift
      break
      ;;
    *)
      echo "${1} is not option"
      ;;
    esac
    shift
  done

  #默认是install指令
  if [ "${1}" != "update" ] && [ "${1}" != "install" ]; then
    cmd='install'
  else
    cmd=${1} && shift
  fi

  if [ "${ENV}" == "test" ];then
    UpgradeCheckTime="600s"
  fi

  pkgUrl=`getPkgDownloadUrl "${@}"`
  #生产环境
  echo "ENV: ${ENV}"
  echo "PKG: ${pkgUrl}"
  #echo "CENTER_SERVER: ${CENTER_SERVER}"

  $cmd "${pkgUrl}"
}

main $@



